﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Ziggyware;
using Shadows2D;

namespace AGrandVenture
{
    class LightManager
    {
        #region Declarations
        private static int MaxLightSources = 20;
        private static Game1 game = null;
        private static ShadowmapResolver shadowmapResolver;
        private static QuadRenderComponent quadRender;
        private static RenderTarget2D screenShadows;
        private static GraphicsDevice graphicsDevice;
        public static List<Light> Lights = new List<Light>();
        public static List<Sprite> lightSources = new List<Sprite>();
        #endregion

        #region Initialization

        public static void Initialize(Game1 gm, ShadowmapResolver smr, QuadRenderComponent qr, GraphicsDevice gd)
        {
            game = gm;
            graphicsDevice = gd;
            shadowmapResolver = smr;
            quadRender = qr;

            for (int i=0; i < MaxLightSources; i++)
            {
                  Lights.Add(new Light(null, new LightArea(gd, 7.25)));
            }
            screenShadows = new RenderTarget2D(gd, gd.Viewport.Width, gd.Viewport.Height);
        }

        #endregion

        #region Light Management

        public static void addLightSource(Sprite lightSource, Color lightColor, double lightSize)
        {
            //Track it regardless of if there is a free light to associate it with
            lightSources.Add(lightSource);

            //Adjust size for scale
            double adjustedSize = 4.499 + (5.5 * lightSize);

            //Look for an empty light and fill it if available
            foreach (Light light in Lights)
            {
                if (light.sprite == null)
                {
                    light.sprite = lightSource;
                    light.color = lightColor;
                    light.area.changeSize(adjustedSize);
                    break;
                }
            }
        }

        public static void addLightSource(Sprite lightSource, Color lightColor, double lightSize, bool flick)
        {
            //Track it regardless of if there is a free light to associate it with
            lightSources.Add(lightSource);

            //Adjust size for scale
            double adjustedSize = 4.499 + (5.5 * lightSize);

            //Look for an empty light and fill it if available
            foreach (Light light in Lights)
            {
                if (light.sprite == null)
                {
                    light.sprite = lightSource;
                    light.color = lightColor;
                    light.flicker = flick;
                    light.area.changeSize(adjustedSize);
                    break;
                }
            }
        }

        public static void removeLightSource(Sprite lightSource)
        {
            //Remove it from the list
            lightSources.Remove(lightSource);

            //Look for an associated light and remove the association
            foreach (Light light in Lights)
            {
                if (light.sprite != null && light.sprite.Equals(lightSource))
                {
                    light.sprite = null;
                    light.position = Vector2.Zero;
                    light.color = Color.White;
                    light.area.changeSize(7.5);
                    break;
                }
            }
        }
        #endregion

        #region Update and Draw

        public static void Update(GameTime gameTime)
        {
            foreach (Light light in Lights)
                if (light.sprite != null)
                    light.Update();
        }

        public static RenderTarget2D Draw(GraphicsDevice gd, SpriteBatch spriteBatch)
        {
            gd.Clear(Color.CornflowerBlue);
            Random random = new Random();

            foreach (Light light in Lights)
            {
                light.originalSize = light.area.LightAreaSize;

                if (light.position != Vector2.Zero)
                {
                    if (light.flicker)
                    {
                        /*
                        if (random.Next(1, 25) == 1)
                        {
                            ran = 1 + (.001f * random.Next(0, 20));
                            if (random.Next(0,1) == 0)
                                light.area.LightAreaSize = new Vector2((light.originalSize.X * ran), (light.originalSize.Y));
                            else
                                light.area.LightAreaSize = new Vector2((light.originalSize.X ), (light.originalSize.Y * ran));
                        }
                         */
                    }
                    light.area.LightPosition = light.position;
                    light.area.BeginDrawingShadowCasters();
                    game.DrawShadowCasters(light.position, light.area.LightSize);
                    light.area.EndDrawingShadowCasters();
                    shadowmapResolver.ResolveShadows(light.area.RenderTarget, light.area.RenderTarget, light.position);
                }
            }
            gd.SetRenderTarget(screenShadows);
            gd.Clear(Color.Black);
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);

            foreach (Light light in Lights)
            {
                if (light.position != Vector2.Zero)
                {
                    spriteBatch.Draw(light.area.RenderTarget, light.area.LightPosition - light.area.LightAreaSize * 0.5f, light.color);
                    light.area.LightAreaSize = light.originalSize;
                }

            }

            //Apply map darkness to shadows
            int ambientLight = (int)(240 * (1 - Tile_Engine.TileMap.Darkness));
            if (ambientLight > 0)
                spriteBatch.Draw(Game1.whiteDotSheet, new Rectangle(0, 0, 1280, 720), new Color(255, 255, 255, ambientLight));
            
            spriteBatch.End();

            gd.SetRenderTarget(null);

            //gd.Clear(Color.Black);

            return screenShadows;
        }
        #endregion


        #region Light Definition
        public class Light
        {
            public Sprite sprite;
            public Vector2 position;
            public LightArea area;
            public Color color;
            public bool flicker;
            public Vector2 originalSize;

            public Light(Sprite go, LightArea a)
            {
                sprite = go;
                area = a;
                color = Color.White;
                flicker = false;

                if (go != null)
                    position = sprite.ScreenCentre;
                else
                    position = Vector2.Zero;
            }

            public void Update()
            {
                if (sprite.Expired)
                {
                    LightManager.removeLightSource(sprite);
                }
                else
                    position = sprite.ScreenCentre;
            }

            public void changeColor(Color c)
            {
                color = c;
            }

            public void changeSize(Vector2 size)
            {
                area.LightAreaSize = size;
            }

            public void changeFlicker(bool bFlicker)
            {
                flicker = bFlicker;
            }
        }
        #endregion
    }
}
